using System;
using System.Collections.Generic;
using System.Collections;
using System.Text;
using System.IO;
using ClipShow2.Storage;
using ClipShow2.MediaTypes;

namespace ClipShow2.LibraryManager
{
    public class ClipTopic
    {
        public ClipTopic()
        {
        }
        public ClipTopic(string keywords, long topicCount, long mediaCount, 
            string thumbnail)
        {
            Keywords = keywords;
            TopicCount = topicCount;
            MediaCount = mediaCount;
            ThumbnailSample = thumbnail;
        }

        public string Keywords = "";
        public long TopicCount = 0;
        public long MediaCount = 0;
        public string Topic = "";
        public string ThumbnailSample = "";
    }

    public class Topics
    {
        public Topics()
        {
            // Define related topics here
            RelatedPhrases.Add("Disney", "Disney World");
            RelatedPhrases.Add("Christmas Eve", "Christmas");
            RelatedPhrases.Add("Birthday", "Birthday Party");

            // Persist noise word file first time
            StorageEngine.PersistTagFile(NoiseWords, NOISE_WORD_FILE);
            StorageEngine.PersistTagFile(KeyPhrases, KEY_PHRASE_FILE);
            StorageEngine.PersistTagFile(WildcardPhrases, WILDCARD_PHRASE_FILE);
            StorageEngine.PersistTagFile(Congugations, CONGUGATE_PHRASE_FILE);
        }
        private const int TOPIC_THRESHOLD = 5;
        private const string NOISE_WORD_FILE = "clipShow_Noise.xml";
        private const string KEY_PHRASE_FILE = "clipShow_KeyPhrase.xml";
        private const string WILDCARD_PHRASE_FILE = "clipShow_WildcardPhrase.xml";
        private const string CONGUGATE_PHRASE_FILE = "clipShow_Congugate.xml";

        private string[] NoiseWords = { "a", "an", "and", "or", "neither", "nor", "the", "them", "we","his", "him", "her", "hers", "us", 
            "their", "have", "has", "am", "had", "is", "not",
            "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "in", "up", "down", "for", "video", "movie",
            "videos", "movies", "with", "what", "that", "which", "how", "when", "why", "of", "by", "take", "taken", "make", "made",
            "our", "you", "your", "at", "on", "off", "thru", "through", "year", "part", "parts", "day", "to", "too", "from",
            "all", "about","go", "goes", "more", "most", "day", "date", "home", "it", "its", "first", "second", "third", 
            "fourth", "fifth", "sixth", "seventh", "eighth", "ninth", "tenth", "house", "before", "after", "prior", "between", 
            "back", "forward", "backwards", "old", "new", "having", "kids", "use", "he", "are", "as", "get", "gets", "do", "does", "did", "who",
            "be", "try", "tries","into","find", "must", "bring", "brought", "going", "this", "will", "shall", "should", "would", 
            "Monday","Tuesday","Wednesday","Thursday","Friday", "Saturday", "Sunday", "together", "choose","chosen","choice", 
            "morning", "time", "life", "dirty", "those", "lives", "she", "he", "yours", "without", "same", "give", "there", "my", "ft", "got",
            "so"};

        private string[] Congugations = { "listen", "work", "open", "expect", 
                                            "meet","play", "grow","sing","visit","build","present", "ride","climb","deliver",
                                            "rest", "help", "gift", "want", "present"};

        private string[] KeyPhrases = { "birthday party", "Birthday Party", "Birthday party", 
            "Disney World", "Disney Land", "Christmas Eve", "Xmas Eve", "Family Vacation", "family vacation", "Family vacation", "Dance Recital", 
            "Easter Egg", "Thanksgiving Day", "Easter Day", "Memorial Day"};

        private string[] WildcardPhrases = { "Uncle X", "Aunt X", "Sister X", "Brother X", "X kids", "X Highlights", 
                                               "Grandma X", "Grandpa X", "X vacation", "X Vacation", "Granddad X", "Grandmother X", "X Program", "X trip", "X Trip", "X Party",
                                           "X party"};

        public sealed class ClipTopicComparer : System.Collections.IComparer
        {
            public int Compare(object first, object second)
            {
                ClipTopic firstInstance = first as ClipTopic;
                ClipTopic secondInstance = second as ClipTopic;
                return secondInstance.TopicCount.CompareTo(firstInstance.TopicCount);
            }
        }

        private Dictionary<string, string> RelatedPhrases = new Dictionary<string,string>();
        private string[] BuildConjugations(string[] source)
        {
            string[] newResults =  new string[source.Length*4];

            int ctr = 0;
            foreach (string item in source)
            {
                newResults[ctr] = item;
                newResults[ctr + 1] = String.Format("{0}ing", item);
                newResults[ctr + 2] = String.Format("{0}s", item);
                newResults[ctr + 3] = String.Format("{0}ed", item);

                ctr += 4;
            }

            return (newResults);
        }

        public string BuildSingleTopic(ClipShowMetadata item)
        {
            // Load noise, keyphrases and wildcards
            KeyPhrases = StorageEngine.GetTagFile(KEY_PHRASE_FILE, KeyPhrases);
            WildcardPhrases = StorageEngine.GetTagFile(WILDCARD_PHRASE_FILE, WildcardPhrases);
            NoiseWords = StorageEngine.GetTagFile(NOISE_WORD_FILE, NoiseWords);
            Congugations = BuildConjugations(StorageEngine.GetTagFile(CONGUGATE_PHRASE_FILE, Congugations));

            Dictionary<string, ClipTopic> temp = FirstPass(item);

            StringBuilder result = new StringBuilder();
            foreach (string term in temp.Keys)
            {
                result.AppendFormat("{0};", term);
            }
            if (result.Length > 0)
            {
                result.Remove(result.Length - 1, 1);
            }
            return (result.ToString());
        }

        private Dictionary<string, ClipTopic> FirstPass(ClipShowMetadata item)
        {
            Dictionary<string, ClipTopic> myTopics = new Dictionary<string, ClipTopic>();
            #region Source descriptions
            if (item.Description.Length > 0)
            {
                Dictionary<string, long> results = PhraseBreaker(item.Description, ' ');
                foreach (string term in results.Keys)
                {
                    if (myTopics.ContainsKey(term))
                    {
                        myTopics[term].TopicCount++;
                        myTopics[term].ThumbnailSample = item.ThumbnailUrl;
                    }
                    else
                    {
                        myTopics.Add(term, new ClipTopic(term, 1, 0, item.ThumbnailUrl));
                    }
                }
            }
            #endregion

            #region Source titles
            if (item.Title.Length > 0)
            {
                Dictionary<string, long> results = PhraseBreaker(item.Title, ' ');
                foreach (string term in results.Keys)
                {
                    if (myTopics.ContainsKey(term))
                    {
                        myTopics[term].TopicCount++;
                        myTopics[term].ThumbnailSample = item.ThumbnailUrl;
                    }
                    else
                    {
                        myTopics.Add(term, new ClipTopic(term, 1, 0, item.ThumbnailUrl));
                    }
                }
            }
            #endregion

            #region Source urls (filenames)
            if (item.Url.Length > 0)
            {
                Dictionary<string, long> results = PhraseBreaker(Path.GetFileNameWithoutExtension(item.Url), ' ');
                foreach (string term in results.Keys)
                {
                    if (myTopics.ContainsKey(term))
                    {
                        myTopics[term].TopicCount++;
                        myTopics[term].ThumbnailSample = item.ThumbnailUrl;
                    }
                    else
                    {
                        myTopics.Add(term, new ClipTopic(term, 1, 0, item.ThumbnailUrl));
                    }
                }
            }
            #endregion

            #region Source urls (directories) if needed
            if (myTopics.Count < 1)
            {
                if (item.Url.Length > 0)
                {
                    // Grab the parent directory name
                    string[] url = Path.GetDirectoryName(item.Url).Split('\\');
                    Dictionary<string, long> results = PhraseBreaker(url[url.Length-1], ' ');
                    foreach (string term in results.Keys)
                    {
                        if (myTopics.ContainsKey(term))
                        {
                            myTopics[term].TopicCount++;
                            myTopics[term].ThumbnailSample = item.ThumbnailUrl;
                        }
                        else
                        {
                            myTopics.Add(term, new ClipTopic(term, 1, 0, item.ThumbnailUrl));
                        }
                    }
                }
            }
            #endregion

            return (myTopics);
        }

        private long MediaCount(ClipShowContent source, string keywords)
        {
            string[] keywordSplit = keywords.Split(';');
            long results = 0;
            foreach (string searchKeyword in keywordSplit)
            {
                foreach (ClipShowMetadata item in source.MediaItems)
                {
                    bool foundIt = ((item.Description.Contains(searchKeyword)) ||
                        (item.Title.Contains(searchKeyword)) ||
                        (Path.GetFileNameWithoutExtension(item.Url).Contains(searchKeyword)));
                    if (foundIt)
                    {
                        results++;
                    }
                }
            }
            return (results);
        }
        private bool CheckForNoise(string source)
        {
            bool result = false;
            foreach (string word in NoiseWords)
            {
                if (source.ToLower().Equals(word))
                {
                    result = true;
                    break;
                }
            }

            if (result)
            {
                return (result);
            }

            // Check for congugations
            foreach (string word in Congugations)
            {
                if (source.ToLower().Equals(word))
                {
                    result = true;
                    break;
                }
            }

            if (result)
            {
                return (result);
            }

            if ((source.ToLower().EndsWith("rd")) || (source.ToLower().EndsWith("st")) ||
                (source.ToLower().EndsWith("nd")) || (source.ToLower().EndsWith("th")))
            {
                try
                {
                    if (Convert.ToInt32(source.Substring(source.Length - 3, 1)) >= 0)
                    {
                        result = true;
                    }
                }
                catch
                {
                    result = false;
                }
            }
            return (result);
        }
        private string Scrubber(string source)
        {
            string result = source;
            if (source.EndsWith("'s"))
            {
                result = source.Substring(0, source.Length - 2);
            }

            if ((source.EndsWith(".") || (source.EndsWith(")")) || (source.EndsWith(";")) ||
                (source.EndsWith("?")) || (source.EndsWith("'")) || (source.EndsWith(","))))
            {
                result = source.Substring(0, source.Length - 1);
            }

            return (result);
        }
        private Dictionary<string, long> PhraseBreaker(string source, char delimeter)
        {
            Dictionary<string, long> results = new Dictionary<string, long>();
            string workingSet = source;

            #region Check for key phrases
            foreach (string keyPhrase in KeyPhrases)
            {
                if (source.Contains(keyPhrase))
                {
                    results.Add(keyPhrase, 1);
                    workingSet = source.Replace(keyPhrase, "");
                }
            }
            #endregion

            #region Check for wild card phrases
            foreach (string wildcard in WildcardPhrases)
            {
                string[] wildSplit = wildcard.Split(' ');
                if (wildSplit[0].Equals("X"))
                {
                    if (source.Contains(wildSplit[1]))
                    {
                        string[] sourceSplit = source.Split(' ');
                        for (int ctr = 1; ctr < sourceSplit.Length; ctr++)
                        {
                            if (sourceSplit[ctr].Equals(wildSplit[1]))
                            {
                                string wildCardPhrase = String.Format("{0} {1}",
                                    Scrubber(sourceSplit[ctr - 1]), Scrubber(sourceSplit[ctr]));

                                if (results.ContainsKey(wildCardPhrase))
                                {
                                    results[wildCardPhrase]++;
                                }
                                else
                                {
                                    results.Add(wildCardPhrase, 1);
                                }
                                workingSet = source.Replace(String.Format("{0} {1}", sourceSplit[ctr-1], sourceSplit[ctr]), "");
                                break;

                            }
                        }
                    }
                }
                if (wildSplit[1].Equals("X"))
                {
                    if (source.Contains(wildSplit[0]))
                    {
                        string[] sourceSplit = source.Split(' ');
                        for (int ctr = 0; ctr < sourceSplit.Length - 1; ctr++)
                        {
                            if (sourceSplit[ctr].Equals(wildSplit[0]))
                            {
                                string wildCardPhrase = String.Format("{0} {1}",
                                    Scrubber(sourceSplit[ctr]), Scrubber(sourceSplit[ctr + 1]));

                                if (results.ContainsKey(wildCardPhrase))
                                {
                                    results[wildCardPhrase]++;
                                }
                                else
                                {
                                    results.Add(wildCardPhrase, 1);
                                }

                                workingSet = source.Replace(String.Format("{0} {1}", sourceSplit[ctr], sourceSplit[ctr + 1]), "");
                                break;

                            }
                        }
                    }
                }

            }
            #endregion

            string[] temp = workingSet.Split(delimeter);
            
            string parenKeeper = "";
            foreach (string s in temp)
            {
                string scrubbed = Scrubber(s);
                if (!CheckForNoise(scrubbed))
                {
                    try
                    {
                        int throwAway = Convert.ToInt32(scrubbed);
                    }
                    catch (FormatException)
                    {
                        if (scrubbed.EndsWith(")"))
                        {
                            parenKeeper = String.Format("{0} {1}",
                                parenKeeper, scrubbed.Substring(0, scrubbed.Length - 1));
                            //string parenfinalTerm = Scrubber(parenKeeper);
                            if (results.ContainsKey(parenKeeper))
                            {
                                results[s]++;
                            }
                            else
                            {
                                results.Add(parenKeeper, 1);
                            }
                            break;
                        }
                        else
                        if (parenKeeper.Length > 0)
                        {
                            parenKeeper = String.Format("{0} {1}", parenKeeper, scrubbed);
                            break;
                        }
                        if (scrubbed.StartsWith("("))
                        {
                            parenKeeper = scrubbed.Substring(1, scrubbed.Length - 1);
                            break;
                        }

                        if (scrubbed.Length > 1)
                        {
                            if (results.ContainsKey(scrubbed))
                            {
                                results[scrubbed]++;
                            }
                            else
                            {
                                results.Add(scrubbed, 1);
                            }
                        }
                    }

                }
            }
            return (results);
        }
    }
}
